import struct
import math
import numpy as np
import wave
import blockAnalyzer
import array
import pyaudio
import blockAnalyzer

class CodificadorDeArchivo(object):
    # Recibe una serie de codigos entre 0 y 7 y genera una seria de Bytes entre 0 y 255
    def __init__(self, file):
        'Variables'
        self.FileStream = open(file, 'rb')
        'Clases'
        self.coder = blockAnalyzer.Codificador() 
        self.fileGenerated = ''
        
    def generarCodigos(self):
        a1 = array.array('B')
        self.FileStream.seek(0,2)
        fileSize = self.FileStream.tell()
        self.FileStream.seek(0)
        a1.fromfile(self.FileStream, fileSize)

        self.coder.dataStart()
        
        for x in range (0,len(a1)):
            self.coder.push(a1[x])
        self.coder.dataEnd()
        self.fileGenerated =self.coder.getArchivo() 

    def imprimirArchivo(self):
        print(str(self.fileGenerated))
        
    def getArchivo(self):
        return self.fileGenerated


def CodificadorDeArchivoAArchivoDeSonido(fileOrigen,fileDestino):
    analizar = blockAnalyzer.blockAnalyzer()
    frecuenciaCodigos = analizar.get_frecuencia_notas(440)
    fileRead = CodificadorDeArchivo(fileOrigen)
    fileWrite = SoundWriter(fileDestino)
    
    fileRead.generarCodigos()
    
    
    codigos = fileRead.getArchivo()
    
    for x in range (0,len(codigos)):
        fileWrite.makeSine(frecuenciaCodigos[codigos[x]], 0.5)
    fileWrite.end()

class SoundWriter(object):
    # Recibe una serie de codigos entre 0 y 7 y genera una seria de Bytes entre 0 y 255
    def __init__(self, file):
        'Constantes'
        self.AMPLITUDE_RESOLUTION = pyaudio.paInt16
        self.SAMPLING_FREQUENCY = 44100
        self.CHANNELS = 2
        'Variables'
        self.wf = wave.open(file, 'wb')
        self.wf.setnchannels(self.CHANNELS)
        self.wf.setsampwidth(4)
        self.wf.setframerate(self.SAMPLING_FREQUENCY)
        'Clases'
        self.fileGenerated = ''
        
        
    def makeSine(self,frecuency,durationSeconds):
        # sample is a signed short int +/- 32768
        amplitude = 32768 - 1
        block = []
        for x in range(0,int(1*self.SAMPLING_FREQUENCY*durationSeconds)):
            block.append(int( amplitude * np.sin( 1.0 * 2*np.pi*frecuency * x/self.SAMPLING_FREQUENCY ) ))
        
        count = len(block)/2
        
        format = "%dh"%(count*self.CHANNELS)
        newBlock = struct.pack( format, *block )
        self.wf.writeframes(newBlock)
        
    def end(self):
        self.wf.close()

